using IQIGame.Onigao.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.Game
{
    public class EntityGroup
    {
        #region Properties
        public int Id { get; }
        public int EntityCount => m_Entities.Count;
        public int PoolTotalCount => m_EntityPool.TotalCount;
        #endregion

        private ObjectPoolBase m_EntityPool;

        private List<Entity> m_Entities;
        private Dictionary<int, Entity> m_EntityMap;

        public EntityGroup(int id, Type entityType, float instanceAutoReleaseInterval, float instanceExpireTime, int sameResCapacity, int totalCapacity)
        {
            Id = id;
            m_EntityPool = FrameworkEntry.ObjectPoolMgr.CreateObjectPool(entityType, id, instanceExpireTime);
            m_EntityPool.AutoReleaseInterval = instanceAutoReleaseInterval;
            m_EntityPool.SameResCapacity = sameResCapacity;
            m_EntityPool.TotalCapacity = totalCapacity;
            m_Entities = new List<Entity>();
            m_EntityMap = new Dictionary<int, Entity>();
        }

        public void OnUpdate(float deltaTime, float unScaledDeltaTime)
        {
            for (int i = 0; i < m_Entities.Count; i++)
            {
                m_Entities[i].OnUpdate(deltaTime, unScaledDeltaTime);
            }
        }

        /// <summary>
        /// 生成一个Entity（从对象池里获取）
        /// </summary>
        /// <param name="id"></param>
        /// <param name="assetName"></param>
        /// <param name="userData"></param>
        /// <returns></returns>
        public Entity Get(int id, string assetName)
        {
            Entity entity = (Entity)m_EntityPool.GetObject(assetName);
            entity.SetGroup(this);
            entity.SetId(id);
            m_Entities.Add(entity);
            m_EntityMap[id] = entity;
            return entity;
        }

        /// <summary>
        /// 从实体组中获取实体。
        /// </summary>
        /// <param name="entityId">实体序列编号。</param>
        /// <returns>要获取的实体。</returns>
        public Entity FindEntity(int entityId)
        {
            if (m_EntityMap.TryGetValue(entityId, out var entity))
            {
                return entity;
            }
            return null;
        }

        /// <summary>
        /// 从实体组中获取实体。
        /// </summary>
        /// <param name="entityAssetName">实体资源名称。</param>
        /// <returns>要获取的实体。</returns>
        public Entity FindEntity(string entityAssetName)
        {
            if (string.IsNullOrEmpty(entityAssetName))
            {
                throw new FrameworkException("Entity asset name is invalid.");
            }

            for (int i = 0; i < m_Entities.Count; i++)
            {
                Entity entity = m_Entities[i];
                if (entity.AssetName == entityAssetName)
                {
                    return entity;
                }
            }

            return null;
        }

        private void InnerHideEntity(Entity entity)
        {
            int entityId = entity.Id;
            if (m_EntityMap.Remove(entityId))
            {
                if (entity.transform != null)
                {
                    entity.transform.parent = null;
                    entity.transform.position = Vector3.zero;
                    entity.transform.localScale = Vector3.one;
                    entity.transform.rotation = Quaternion.identity;
                }
                m_Entities.Remove(entity);
                m_EntityPool.PutBackObject(entity);
            }
            else
            {
                LogGame.LogError("隐藏实体失败，实体对象已不在实体组中，可能已经被隐藏。");
            }
        }

        public void HideEntity(int entityId)
        {
            HideEntity(FindEntity(entityId));
        }

        public void HideEntity(Entity entity)
        {
            if (entity == null)
            {
                return;
            }
            entity.CancelLoading();
            InnerHideEntity(entity);
        }

        public void HideAll()
        {
            for (int i = m_Entities.Count - 1; i >= 0; i--)
            {
                HideEntity(m_Entities[i]);
            }
        }

        public void Dispose()
        {
            HideAll();
            FrameworkEntry.ObjectPoolMgr.DestroyObjectPool(m_EntityPool);
        }
    }
}
